﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="TestSubtractIndexedDenseVector.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.Tests.DenseVectorTest.DoubleExtensions
{
    #region Usings

    using System;
    using System.Globalization;

    using ExulLibrary.Exceptions;
    using ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions;

    using NUnit.Framework;

    #endregion

    /// <summary>
    ///     Test suite for <see cref="DenseVectorExtensions.Subtract(DenseVector{double},int[],DenseVector{double})"/>.
    /// </summary>
    [TestFixture]
    [Category("ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions.DenseVectorExtensions")]
    public sealed class TestSubtractIndexedDenseVector
    {
        /// <summary>
        ///     Tests the method when indexes specify existing elements.
        /// </summary>
        [Test]
        public void WhenMinuendIndexesAreValid()
        {
            // Arrange
            var minuend = new DenseVector<double>(new double[] { 10, 20, 30 });
            var subtrahend = new DenseVector<double>(new double[] { 1, 2 });
            var minuendIndexes = new[] { 0, 2 };

            // Act
            minuend.Subtract(minuendIndexes, subtrahend);

            // Assert
            Assert.That(minuend.Values, Is.EquivalentTo(new double[] { 9, 20, 28 }));
        }

        /// <summary>
        ///     Tests the method when minuendIndexes parameter is empty collection.
        /// </summary>
        [Test]
        public void WhenMinuendIndexesCollectionIsEmpty()
        {
            // Arrange
            var minuend = new DenseVector<double>(new double[] { 10, 20, 30 });
            var subtrahend = new DenseVector<double>(new double[] { 1, 2 });
            var minuendIndexes = new int[0];

            // Act
            minuend.Subtract(minuendIndexes, subtrahend);

            // Assert
            Assert.That(minuend.Values, Is.EquivalentTo(new double[] { 10, 20, 30 }));
        }

#if SAFE

        /// <summary>
        ///     Tests the method when minuend parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenMinuendIsNull()
        {
            // Arrange
            var subtrahend = new DenseVector<double>(2);
            var minuendIndexes = new[] { 0, 2 };

            // Act and Assert
            Assert.That(
                () => DenseVectorExtensions.Subtract(null, minuendIndexes, subtrahend),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("minuend"));
        }

        /// <summary>
        ///     Tests the method when minuendIndexes parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenMinuendIndexesIsNull()
        {
            // Arrange
            var minuend = new DenseVector<double>(3);
            var subtrahend = new DenseVector<double>(2);

            // Act and Assert
            Assert.That(
                () => minuend.Subtract(null, subtrahend),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("minuendIndexes"));
        }

        /// <summary>
        ///     Tests the method when subtrahend parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenSubtrahendIsNull()
        {
            // Arrange
            var minuend = new DenseVector<double>(3);
            var minuendIndexes = new[] { 0, 2 };

            // Act and Assert
            Assert.That(
                () => minuend.Subtract(minuendIndexes, null),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("subtrahend"));
        }

        /// <summary>
        ///     Tests the method when an minuend index is negative or greater than or equal to the number of elements
        ///     of minuend vector.
        /// </summary>
        /// <param name="position">
        ///     The position of index in the storage.
        /// </param>
        /// <param name="minuendIndex">
        ///     The index of minuend element.
        /// </param>
        [Test]
        public void WhenAnMinuendIndexIsOutOfRange([Values(0, 1)] int position, [Values(-1, 3)] int minuendIndex)
        {
            // Arrange
            var minuend = new DenseVector<double>(3);
            var subtrahend = new DenseVector<double>(2);
            var minuendIndexes = new int[2];
            minuendIndexes[position] = minuendIndex;

            // Act and Assert
            var parameterName = string.Format(CultureInfo.InvariantCulture, "minuendIndexes[{0}]", position);
            Assert.That(
                () => minuend.Subtract(minuendIndexes, subtrahend),
                Throws.TypeOf<ElementIndexIsOutOfRangeException>().With.Property("ParamName").EqualTo(parameterName));
        }

#endif
    }
}